package ar.com.angrymachine.hunter.gameplay;

import java.util.Vector;

import ar.com.angrymachine.hunter.GameSettings;
import ar.com.angrymachine.utils.Util;

public class Character implements Leveled, Cloneable
{
    protected double attackPower;
    public double attackRate;
    public double naturalExplorationSkill;
    public double naturalFightingSkill;
    public double naturalDisarmSkill;
    public double naturalMagicSkill;
    private double maxHealth;
    private double health;
    public int gold = 0;
    protected Vector inventory = new Vector();
    protected int level = 1;
	private boolean isDead = false;
    
    Character(double maxHealth, double attackPower, double attackRate, int level)
    {
        this.maxHealth = maxHealth;
        this.health = maxHealth;
        this.attackPower = attackPower;
        this.naturalExplorationSkill = 1.0;
        this.naturalFightingSkill = 1.0;
        this.naturalDisarmSkill = 1.0;
        this.naturalMagicSkill = 1.0;
        this.attackRate = attackRate;
        this.level = level;
    }
    
    public void healCompletely()
    {
    	health = maxHealth;
    }
    
    public void setMaxHealth(double newMax)
    {
    	maxHealth = newMax;
    	if(health > maxHealth)
    	{
    		health = maxHealth;
    	}
    }
    
    public double getMaxHealth()
    {
    	return maxHealth;
    }
    
	public boolean isDead()
	{
		return isDead;
	}
    
    public double getHealth()
    {
    	return health;
    }
    
    protected void damageHealth(double damage)
    {
        health -= damage;
        if(health < 0)
    	{
        	health = 0;
        	isDead = true;
    	}
    }
        
    public Object clone()
    {
        try
        {
            return super.clone();
        }
        catch (CloneNotSupportedException e)
        {
            return null;
        }
    }
    
    public int getLevel()
    {
        return level;
    }

    private interface ModifierRetriever
    {
    	double retrieve(InventoryObject obj);
    }
    
    public void receiveHealing(double toAdd)
    {
    	health += toAdd;
    	if(health > maxHealth)
    	{
    		health = maxHealth;
    	}
    }
    
    public void receiveAttack(double damage)
    {
    	damageHealth(damage);
    }
    
    public double getAttackPower()
    {
    	return getFinalValue(attackPower, new ModifierRetriever()
		{
			public double retrieve(InventoryObject obj)
			{
				return obj.attackPowerModifier;
			}
		});
    }
        
    public double getExplorationSkill()
    {
    	return getFinalValue(naturalExplorationSkill, new ModifierRetriever()
		{
			public double retrieve(InventoryObject obj)
			{
				return obj.explorationSkillModifier;
			}
		});
    }

    public double getFightingSkill()
    {
    	return getFinalValue(naturalFightingSkill, new ModifierRetriever()
		{
			public double retrieve(InventoryObject obj)
			{
				return obj.fightingSkillModifier;
			}
		});
    }

    public double getMagicSkill()
    {
    	return getFinalValue(naturalMagicSkill, new ModifierRetriever()
		{
			public double retrieve(InventoryObject obj)
			{
				return obj.magicSkillModifier;
			}
		});
    }
    
    public double getDisarmPower()
    {
    	return getFinalValue(naturalDisarmSkill, new ModifierRetriever()
		{
			public double retrieve(InventoryObject obj)
			{
				return obj.disarmSkillModifier;
			}
		});
    }
    
    private double getFinalValue(double base, ModifierRetriever retriever)
    {
        for (int i = 0; i < inventory.size(); i++)
        {
            InventoryObject obj = (InventoryObject) inventory.elementAt(i);
            base *= retriever.retrieve(obj);
        }
    	return base;
    }
    
    public double getHitDamage()
    {
        double damage = attackPower * getFightingSkill();
        damage = Util.getVariation((int)damage,GameSettings.HIT_DAMAGE_VARIATION);
        return damage;
    }
    	
    public void receiveSpell(Spell spell)
    {
        spell.castOnCharacter(this);
    }
}
